/*******************************************************************************
 * The MOSES project, model based software engineering of networked embedded systems.
 * 
 * Copyright (C) 2010-2013, University of Applied Sciences Wildau,
 * Telematics Research Group, http://www.tm.th-wildau.de/research-group
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses>.
 * 
 * Contributors:
 *     University of Applied Sciences Wildau - initial API and implementation
 * 
 * If you are interested in a commercial license please contact us via 
 * e-mail: ralf.vandenhouten@th-wildau.de.
 ******************************************************************************/
package de.thwildau.tm.moses.thrift.formatting;

import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.CLOSING_BRACKET;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.CLOSING_CHEVRON;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.CLOSING_CURLED_BRACKET;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.COLON;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.COMMA;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.EQUAL;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.OPENING_BRACKET;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.OPENING_CHEVRON;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.OPENING_CURLED_BRACKET;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.SEMICOLON;
import static de.thwildau.tm.moses.thrift.util.ThriftKeyword.THROWS;

import java.util.List;

import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter;
import org.eclipse.xtext.formatting.impl.FormattingConfig;
import org.eclipse.xtext.util.Pair;

import de.thwildau.tm.moses.thrift.services.ThriftGrammarAccess;

/**
 * This class contains custom formatting description.
 * 
 * @author Thomas Kistel
 * @version $Revision: 759 $
 * @see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#formatting
 */
public class ThriftFormatter extends AbstractDeclarativeFormatter {

	private static final String SPACE = " ";

	@Override
	protected void configureFormatting(FormattingConfig c) {
		ThriftGrammarAccess g = (ThriftGrammarAccess) getGrammarAccess();

		// Comments
		c.setLinewrap(0, 1, 2).before(g.getSL_COMMENTRule());
		c.setLinewrap(1, 1, 2).around(g.getML_COMMENTRule());

		// Includes
		c.setLinewrap(1, 1, 2).around(g.getIncludeRule());
		// Namespaces
		c.setLinewrap(1, 1, 2).around(g.getNamespaceRule());
		// Typedef
		c.setLinewrap(1).after(g.getTypeDefRule());
		// Const
		c.setLinewrap(1).before(g.getConstRule());

		// LineBreaks for sub-rules
		c.setLinewrap(1).after(g.getEnumElementRule());
		c.setLinewrap(2).after(g.getFunctionRule());
		// LineBreaks for Fields within Struct, Exception and Union
		c.setLinewrap(1).after(g.getStructAccess().getFieldsAssignment_4());
		c.setLinewrap(1).after(g.getExceptionAccess().getFieldsAssignment_3());
		c.setLinewrap(1).after(g.getUnionAccess().getFieldsAssignment_4());

		// LineBreaks for Elements within Senum
		c.setLinewrap(1).after(g.getSenumAccess().getElementsAssignment_3_0());

		// insert SPACES around '=' and 'throws'
		for (Keyword k : g.findKeywords(EQUAL.toString(), THROWS.toString())) {
			c.setSpace(SPACE).around(k);
		}
		// Remove spaces for Brackets
		List<Pair<Keyword, Keyword>> brackets = g.findKeywordPairs(
				OPENING_BRACKET.toString(), CLOSING_BRACKET.toString());
		for (Pair<Keyword, Keyword> pair : brackets) {
			c.setNoSpace().around(pair.getFirst());
			c.setNoSpace().before(pair.getSecond());
		}

		// Indentation and Line for Curled Brackets
		for (Keyword k : g.findKeywords(OPENING_CURLED_BRACKET.toString())) {
			c.setIndentationIncrement().after(k);
			c.setLinewrap(1).after(k);
		}
		for (Keyword k : g.findKeywords(CLOSING_CURLED_BRACKET.toString())) {
			c.setIndentationDecrement().before(k);
			c.setLinewrap(1).after(k);
		}
		// remove LineBreaks around ':'
		for (Keyword k : g.findKeywords(COLON.toString())) {
			c.setNoLinewrap().around(k);
			c.setNoSpace().before(k);
			c.setSpace(SPACE).after(k);
		}
		// remove LineBreaks and spaces around Chevrons
		for (Keyword k : g.findKeywords(OPENING_CHEVRON.toString())) {
			c.setNoLinewrap().around(k);
			c.setNoSpace().around(k);
		}
		for (Keyword k : g.findKeywords(CLOSING_CHEVRON.toString())) {
			c.setNoLinewrap().around(k);
			c.setNoSpace().before(k);
		}
		/*
		 * remove spaces and LineBreaks before ',' and ';' (not for Elements and
		 * Fields or after a Function)
		 */
		for (Keyword k : g.findKeywords(SEMICOLON.toString(), COMMA.toString())) {
			c.setNoLinewrap().before(k);
			c.setNoSpace().before(k);
		}
		/*
		 * Remove spaces before "," and ";" for Elements within Const, Enum and
		 * Senum
		 */

		c.setNoSpace().before(
				g.getConstMapAccess().getListSeparatorParserRuleCall_1_1_3());
		c.setNoSpace().before(
				g.getEnumElementAccess().getListSeparatorParserRuleCall_2());
		c.setNoSpace().before(
				g.getSenumAccess().getListSeparatorParserRuleCall_3_1());
		/*
		 * Remove spaces before "," and ";" for Fields within Struct, Exception
		 * and Union
		 */
		c.setNoSpace().before(
				g.getFieldAccess().getListSeparatorParserRuleCall_7());

		// Remove spaces before "," and ";" after Functions
		c.setNoSpace().before(
				g.getFunctionAccess().getListSeparatorParserRuleCall_6());
		// Remove spaces before "," and ";" after Const
		c.setNoSpace().before(
				g.getConstAccess().getListSeparatorParserRuleCall_5());
		// Remove spaces before "," and ";" in Elements within Annotations
		c.setNoSpace().before(
				g.getAnnotationElementAccess()
						.getListSeparatorParserRuleCall_3());
		/*
		 * Remove spaces before "," and ";" in Elements within ConstList and
		 * ConstMap
		 */

		c.setNoSpace().before(
				g.getConstListAccess().getListSeparatorParserRuleCall_1_1_1());
		c.setNoSpace().before(
				g.getConstMapAccess().getListSeparatorParserRuleCall_1_1_3());

		// Remove spaces before ':' when it is use in a FieldID
		// for (Keyword k : g.findKeywords(COLON.toString())) {
		// c.setNoSpace().before(k);
		// }
//		c.setNoSpace().before(g.getFieldIDAccess().getColonKeyword_1());
//		// c.setNoSpace().range(g.getFieldAccess().getFieldIdFieldIDParserRuleCall_0_0(),
//		// g.getFieldAccess().getTypeAssignment_2());
//		c.setNoSpace().between(
//				g.getFieldIDAccess().getLONGTerminalRuleCall_0(),
//				g.getFieldIDAccess().getColonKeyword_1());
//		c.setNoSpace().after(g.getFieldIDAccess().getLONGTerminalRuleCall_0());
//		c.setNoSpace().around(g.getFieldIDAccess().getColonKeyword_1());
//		c.setNoSpace().range(g.getFieldIDAccess().getLONGTerminalRuleCall_0(),
//				g.getFieldIDAccess().getColonKeyword_1());
//		// Add a space after a FieldID
//		c.setSpace(SPACE).after(g.getFieldIDAccess().getRule());

	}
}
